Hey there.
Welcome back.
This lecture is going to be a little fun because we're going to learn about a new service called the
Tween Service, which allows you to animate values in your game.
The result of this ability to tween or animate the values in your game allows you to do different things,
like maybe animate the position of objects from one place to another.
You could animate the colors of objects, you could animate the lighting in your game and there's so
much more things you could do with the tween service.
So what exactly is the tween service?
Well, the Roblox documentation should be able to help us out.
Tweens, which are the objects created by the tween service, are used to interpolate the properties
of instances.
These can be used to create animations for various Roblox objects.
Almost any numeric property can be tweened using tween service.
Note that only specific types of properties can be used with tween service.
The types of properties that can be tweened are going to be numbers, booleans, see frames, rect objects,
or the rect data type color threes Udims which is for UI vector twos, vector threes and enum items.
Tween services constructor function tween service create takes information about the animation and generates
the tween object, which can be used to play the animation.
Note that tweens can animate multiple properties at the same time.
Details on how the interpolation of the tween is to be carried out are given in the tween info parameter
of the create constructor.
The tween info data type includes a range of properties that can be used to achieve various styles of
animations, including reversing and looping.
Tweens.
Multiple tweens can be played on the same object at the same time, but they must not be animating the
same property.
If two tweens attempt to modify the same property, the initial tween will be cancelled and overwritten
by the most recent tween.
Although other methods exist for tweening objects such as tween size and position.
For GUI objects, the tween service allows multiple properties to be modified, and for the animation
to be paused and canceled at any point.
If we take a look at the constructor function, which is called create, it has three parameters.
The first parameter is going to be the instance that needs to be tweened.
The tween info is going to describe how this animation is going to play out.
And then this last parameter is a table that's going to contain a dictionary of properties.
So it's going to be the name of the property.
And then the target value that we're going to tween towards.
Let's go ahead and take a look at a tween info.
So it says a tween info data type stores parameters for the constructor to specify the behavior of the
tween.
And it has a constructor tween info dot new and it accepts several different parameters.
The first is going to be the time or the duration of the tween.
The next is going to be the easing style of the tween, the easing direction, whether or not the tween
repeats, whether or not the tween reverses, and the delay time before playing the tween.
Thankfully, Roblox gives us some examples of what the different easing styles and easing directions
do.
So they give us several graphs with the easing direction first set to N, and it tells us each of the
different styles.
So these are all the styles that are available for the easing style.
For example linear sine quad a whole bunch of different mathematical functions.
But if we take a look at the graphs here x represents the number.
So this bottom left represents the starting point.
And then this represents the goal point.
So over time which is t this is how our value is going to change when it's set to the linear easing
style.
This is what it looks like on sine.
This is quad.
This one's cubic quarte quinte exponential circular back bounce and elastic.
And then these graphs also change depending on the easing direction.
So if we look at an easing direction of out you can see that linear stays the same.
But this time what you should notice is that all of these graphs basically got flipped.
So now sine looks like this.
This is how the value is going to change over time.
Same thing with exponential.
You can see how elastic has changed as well as bounced.
Bounce basically flipped itself.
And then with the easy direction set to in and out, this is what the values are going to look like.
You can see that bounce starts bouncing at the beginning, then it reverses and bounces back at the
end.
So basically does the tween for both the beginning and the ending.
When you're set to in and out, when you're set to out, it does the tween basically at the end.
And then when the easing direction is set to in, it does the fancy tween thing at the beginning of
the tween and then it gradually reaches the end.
So those are the different easing directions, each with their own easing styles and how they influence
them.
So let's go ahead and take a look at how we can use the tween service in our scripts.
The first example I want to go ahead and do is tweening the color of a part.
So here's my part right here in the workspace.
Let me add a script inside of it, and let's make a reference to my part, which is simply going to
be script dot parent.
And we want to be able to tween the color of the part.
So let's go ahead and pull in the tween service.
It's going to be game get service tween service.
And we need to create a brand new tween for our part.
So we need to call the create function.
And we need to pass it the instance between info and the goal properties we want to tween to.
So the instance is going to obviously be our part.
And then we need to pass some information about how we want to play this tween.
So let's create a new tween info.
And it's going to be the global of tween info.
So this is a data type.
And we need to use a constructor to create a new tween info.
And then here we can pass a whole bunch of different optional parameters for how we want to customize
the tween.
So just for this example, let's pass a value of one for the time and then the rest.
We're just going to leave at their defaults.
This is going to be our tween info.
And we need to pass this to the tween service.
And then we need to give it the property that we want to tween.
In this case we want to tween the color property of our part.
So we need to make sure that the key is the exact same name as the property for our part.
and we need to set this equal to a new color three or the color three we want to tween to.
So let's make it a little bit random.
Let me create a random number generator here.
So we're going to do RNG equal to random dot new.
And then we're going to create a new color three.
So color three dot new.
And then for each of the red green and blue number components we're just going to do RNG next number.
And we're just going to randomly generate a number for each of the RGB values.
And then once we create the tween we're not done yet because this function is going to return to us
a tween instance.
So we can call a variable tween and set that equal to the return from the create function.
And if we type out the tween here, as you can see it is of the type tween.
It is a tween instance, and this tween instance has several different properties and events and functions
that we can use.
So for example, to start the tween we can call the play function starts playback of a tween.
Note that if playback has already stopped calling, play has no effect unless the tween has finished
or has stopped.
So this is how we can start playing the tween.
And then the tween also has some events in it.
The most notable is going to be the completed event and it says fires when the tween finishes playing
or when stopped when calling the cancel function.
So let's refer to this event and let's connect a lambda function to it.
And all we're going to do is we're just going to print that the tween completed.
So with this code that we now have, let's go ahead and run our game and see if the color of our part
changes.
So if we hit run.
Well, it looks like it did.
It changed to a slightly weird white color, maybe a more beige color.
And we did print the tween completed.
Unfortunately, it didn't really pick a good random color.
So actually let's let's increase the tween info to like maybe five seconds and then let's run it and
see what color we get.
Okay, look at that.
It's slowly changing color.
And then eventually there we go.
The tween completed and it's a nice little purplish blue color.
Let's run the game again.
And let's take a look at how the color property for our part changes over time.
So if we select the part you're going to see that the color property is slowly changing over time until
it reaches the end of the tween and our tween completes.
And this is our new color.
Very cool.
Now if we remember in the documentation, we can tween more than one property at once.
So another example, maybe we want to tween the size of the part at the same time that we're tweening
the color of the part.
So let's create a variable, let's call it new size.
And this is going to be equal to our parts size.
And then let's add a new vector three.
And let's increase the size of this part on I don't know let's increase it on the x axis by like six
stuts.
And then inside of our goal table, let's actually move it to another variable.
We'll call it goal that's equal to a table.
And then let's copy what we have in here.
Paste it in there and we'll pass goal to the tween service create function.
And then the other property we want to go ahead and tween is going to be the size.
And that's going to be equal to our new size.
So let's go ahead and run the tween now and look at that five seconds.
Over time our part is changing color.
But it is also increased in size by six studs on the x axis.
Really cool.
Let's go ahead and do another example.
Let's go ahead and tween the time inside of the lighting service.
So let's tween this value right here.
Clock time.
So let me create a new script and service.
Script service.
Let's go ahead and get the tween service again.
And I want to have a little bit more fun here.
And let's have this tween loop or go in an infinite cycle.
So to do that what we need to do is we need to create a new tween on the lighting service so we could
do game, get service lighting.
We're going to have to pass a tween info.
So let's create a new tween info here.
Call the variable tween info.
And that's going to be equal to tween info dot new the time.
Let's do let's do 10s the easing style.
Let's do the easing style of linear.
We're going to set the easing direction to just the regular one of in.
It doesn't really matter which one we pick because it's not going to change for this particular easing
style.
So we're just going to do in.
And then we want the tween to basically go on for infinity.
And in order to do that, we need to set the repeat count equal to negative one which tells the tween
service, hey, this is going to be a tween that goes on forever and ever and ever.
And then finally, do we want this tween to reverse?
We don't because we want it to go in a loop.
So we're going to set that equal to false.
So now we can pass this to the create function.
And then finally we need to give it the property table.
In this case we want to change the clock time equal to 24.
Because what's going to happen is once the clock time reaches 24, it's going to set itself to zero,
and then we're going to be able to loop again.
And just to make sure we're going to loop properly, let's set the lighting services clock time to zero.
So actually let us make a variable for the lighting service.
We'll call it lighting equal to game and get service lighting.
That way we can pass that variable to the create function.
And before we play our tween, let's go ahead and set the clock time and the lighting service to zero.
And then let's go ahead and store the result of this constructor in our variable.
So that way we can play the tween.
So now let's go ahead and run our game.
And let's see if we can find the sun.
There's the sun.
It's going around.
And then sunset.
Boom.
There's the moon going around.
And then eventually moon's gone and the sun rise is back to a sunset.
Very cool.
Let's go ahead and take a look at the clock time.
So as you can see it gets set to zero and then it increases towards 24 again.
So we're basically going to loop forever.
So once this hits 24 it should go back to zero.
There we go back to zero.
And we are looping again.
So this is our infinite lighting tween.
Now one important thing I want to mention with the tween service is that you should typically avoid
playing tweens on the server.
This is because as the tween interpolates each frame on the server, it has to send that updated information
to all of the clients in the game at each frame, or each step of the twin.
This will result in tweens looking choppy on the client due to the property being replicated every single
frame, and it's also going to result in higher network usage from your server to your clients.
So as the server continues to update and move something or do whatever with a tween.
Every single client in your game is also going to have to do things, but it's going to look like choppy.
It's not going to look very nice.
So instead, what we should do is we should have a way where we can create a tween or basically create
a tween on the server, but instead the server is going to send that information to every single client
in the game.
So that way every single client plays the tween locally on their copy of the game, so it looks nice
and smooth.
So let's just imagine that every single client's playing a very smooth tween, and then once the tween
is over, all the server needs to do is just instantly update the property that we're tweening to the
goal property.
So that way any new clients that join the game in the future will have whatever property we tweened
at the correct goal mark, and then if the server needs to tween it again to a new position, it can
just send all that information to the clients.
The clients can play those tweens.
So it's nice and smooth.
And then once the tweens are over, the server can just instantaneously move the part to the correct
position.
So as an example of this choppiness, let's take a look at the tween that is tweening the color and
the size of our part.
We're doing it from a service script.
So this is a server side tween.
But let's go ahead and play the game and see what the tween looks like on the client.
And you're going to notice that the tween didn't look that bad because we didn't really move it that
much.
And the tween was quite short.
So actually, before we do anything, let's just wait, uh, a few seconds.
So that way the client can load into the game and then let's make the tween longer, like let's do 10s
and then let's increase the size on the x axis by a much larger number like 50.
And then let's play the game.
And right now it doesn't actually look too bad.
You can see it slightly jittering, but it's not that bad.
And that's because I'm hosting this server locally on my computer, so there isn't really any big network
delay or replication issues.
But trust me, if you publish the game and you play twins on the server, all of the clients in your
game are going to notice that the twins are very jittery and they're not that smooth.
So we need to fix this by creating some kind of system that tells all of the clients to play the tween
locally, instead of the server having to play the tweens.
So let's actually work on that together as like a little mini project with the tween service.
Let's create a module script and let's place it in replicated storage.
And let's call this module script.
Uh, I don't know.
We'll call it something like Better Tween.
And we're going to use this module script to create tweens on the server.
And then this module script is going to handle sending that information to all the clients in our game.
The clients playing the tween.
And then when the tween is over, we can have the server apply all of the properties that are in the
goal table.
So let's rename this module here.
We're going to do control shift R to rename it.
We're just going to call it better tween.
And then let's go ahead and create a function inside of this table.
Better tween.
We're going to use a colon to just kind of pronounce this function as a method.
And let's just call it we could call it create similar to the tween service.
Or we could just call it tween as well, since this is technically going to play the tween for us,
and we're going to do the exact same thing as the tween service, we're going to need to be passed an
instance, the tween info for the tween as well as a goal table.
And then basically what we can do from this point is we can use something like a remote event and fire
to all of the clients in the game.
What instance needs to be tween?
Here's the tween info for it as well as the goal.
So the clients can play those tweens.
And then when the tween is over, we'll have the server apply all of the goal properties.
So let's create a remote event.
Let's just make it a child of our module.
And we'll just call this event play tween.
And then up here we can make a reference to it.
We'll just call it event.
And that's going to be equal to script dot play tween.
And then basically what we want to do is we just want to use our event and we want to fire to all clients.
So fire all clients and we need to send them some information.
We need to send them the instance.
We need to send them the tween info, and we need to send them the goal.
So that way they can play the tween.
So then we are going to need a local script on the client to listen to that event.
So let's add one.
Inside of starter player scripts, we'll create a new local script.
We'll make a reference to replicated storage since that is where our module is stored.
So we'll do game get service, replicated storage.
And then we need a reference to our event.
So we'll just call this event as well.
And that's going to be equal to replicated storage dot better tween dot play tween.
Then we need to listen on the client side.
So on client event I'm going to connect a function to this event.
And we're going to be passed the instance that we need to tween the tween info and the goal property.
And then here on the client is where we can basically actually require the tween service.
So we can do game, get service, tween service.
And then we can just basically do tween service, create and pass the instance, the tween info and
the goal.
And then we can just play the tween.
I don't technically need to store the return of this inside of a variable, unless I need to access
the events or something.
I can call the play function directly on the return value of this tween.
But just to make it a little bit more readable, let's go ahead and make a variable called tween, and
then we'll call the play function on the tween.
So now just as a quick test to make sure that data is being passed properly to the clients, let's head
over to the script for handling our color part.
And instead of creating the tween and playing it on the server, let's go ahead and require our better
tween module instead so we can do game, get service replicated storage dot better tween.
And we need to require that module.
And then instead of doing tween service create, all we need to do is we just need to call the tween
function and pass our instance, our tween info and our goal.
So let's go ahead and see if this works by hopping into the game and playing.
And let's go ahead and see what happens.
Uh oh.
We've got an error inside of our local script on line seven.
Argument two missing or nil.
So let's go ahead and take a look at what this error message means.
So the argument number two is missing.
Or aka our tween info did not get passed to our client.
Why is that what's going on.
So let's figure out what's going on real quick.
And let's print the instance, the tween info and the goal table.
And then let's play our game again and let's go ahead and see what we get.
We get nil nil and we get only our goal table.
That is an issue, right?
So what's going on here is that the first value is nil, because the client may not have replicated
this part on their local copy of the game yet.
So to account for that, if there is no instance, then we're just going to simply not do anything.
And that's because this instance was not yet replicated to the client.
So we're just going to not do anything.
Now, I can fix this issue quite easily by setting a property in the workspace called streaming enabled
to false.
So that way when the player joins the game, all of the parts in the workspace will be instantaneously
available.
So I won't run into this issue right away.
So let's just play test the game real quick.
And actually let's move this print statement to be the first thing.
And then let's see if we fix the first argument okay.
We're still getting nil for some reason.
So that might be because we're not passing the correct argument to the tween function.
So let's go back to our script.
Ah, that's the issue.
I don't know why I just typed instance here.
What we need to pass here is the part.
The part okay.
Now if we play test the game and we take a look at the arguments there, we get our part which is right
there in the workspace.
We get our goal table, but our tween info is still missing what is going on?
Well, unfortunately this is a Roblox limitation.
We are not able to pass tween infos through remote events, so a way to circumvent this issue is that
we should instead pass a table to the client that contains all of the arguments for the tween info,
and then the client can create the tween info, you know, on the client side.
So what we should do instead here on the server side in our module script is we should create a new
table.
I'm just going to call it tween data.
And what it's going to be equal to is just a list of all of the properties for the tween info.
So if we look at tween info dot new, these are the properties that we need to pass in order to our
array.
So the first one is going to be time.
So let's do tween info dot time.
This is a property that exists within our tween info.
Then we also need to get the easing style.
So we're going to do easing style.
And then actually to make this a little bit easier to see.
So we can actually see the properties appearing.
I'm going to do something a little bit fancy here.
I'm going to type annotate this as a tween info.
Don't worry about this.
For right now.
We're going to learn about type annotation much later in the course.
But just for readability sake and teachability sake, I'm going to denote this as a tween info.
So that way the linter or the intellisense or the autocomplete knows what this is.
And now we can see all of the properties.
So we've already got the time.
We've already got the easing style.
The next thing we need to get is the easing direction.
The next thing is going to be the repeat count.
The next property is going to be whether or not this tween reverses.
And finally we're going to need the delay time property.
So now instead of passing this tween info to the client, let's pass the tween data instead.
And then back in our local script.
When we get this tween data, we basically need to take all of those values inside of the array and
pass it to the constructor for the tween info dot new.
So we need to pass all those values into this constructor and then create our own tween info and that
will get passed to the create function.
So let me just fix this here and rename that to tween data.
The easiest way to do this is to use a function in the table library called table dot unpack.
It says returns all elements from the given list as a tuple or a list or whatever.
It's just going to toss all of the values inside of our array and pass it to our constructor.
So we're just going to do table dot unpack tween data.
Okay.
So now let's play test the game and see if we get any issues.
And look at that.
No issues.
And we are playing the tween on the client side.
We got our color part successfully on the client.
We got all of the information we needed for the tween info, and we also got our goal table.
Now there's another issue we need to fix if we take a look at the server side because the server did
not play the tween, this is what the part looks like on the server.
But for my client the part looks like this.
This is going to be an issue, because if you want to sync these changes to any new clients that join
the game in the future, we need to set the goal properties on this part on the server.
So actually let me just copy that.
Let's go to the client view.
Let's copy the color.
Let's paste that there.
And then let's copy the size as well.
And we'll paste that in the size as well.
So this is what we want our part to look like on the server.
So in order to do that, what we need to do inside of our better tween module is we need to wait until
the tween is over.
So we need to include the time, the delay time.
If the tween repeats, we basically need to calculate the total time we need to wait.
And then after that total time is up, we can apply all of the properties on our tween.
So let's go ahead and create a variable.
And we're going to call this total time.
And the total time is going to be equal to the tween info dot time.
And then this is going to have to be added with the tween info dot delay time.
And then we need to multiply these two values by the number of time this tween repeats.
So we can do multiply by tween info dot repeat count.
Now there's one more thing we need to do.
We need to add one to the repeat count.
Why do we need to do this.
Well it's because the repeat count by default is going to be a value of zero, which basically means
the tween plays once.
And if we multiply these values by zero, our total time is going to be zero.
And that's not correct.
So if the tween info repeat count is set to one, that means we need to add that extra one to multiply
the time, for example, by two, which means there is two tweens playing because the repeat count is
set to one.
So now what we need to do is we basically need to delay a function from running for this amount of time.
And then once that time is over, we apply all of the properties on our part.
And a way we can do this is using the task library, which we learned about in a previous lecture.
Let's go ahead and use the task dot delay function to delay for this total time.
We're going to delay a function from executing and once that time is over, we can basically just loop
through all of the properties inside of the goal table and apply those properties on our instance.
So we can do for every single property, name and value inside of pairs goal table.
What we want to do is we want to refer to our instance, index it with this particular property name
and set it equal to the new value.
So now let's go ahead and play our game.
And here it is Tweening on the client side.
And then eventually once the tween is finished.
Let's just wait a few more seconds.
Okay.
The tween should be done if we go and check the server view.
Look at that.
The server has also updated the property to match the new color and the new size that we assign for
in our tween.
So now any future clients that join our game are going to see the size and the color of our property
set to the new correct size and color.
But we have another issue.
The other issue is what if we played a tween on this instance while another tween was being waited for,
and this other tween delays sets the properties while we're waiting for the tween on the other object.
So I'll show you what I mean.
Let's say we tween right.
We're going to tween, which takes 10s.
But let's say, I don't know, five seconds down the line in our game, the tween plays on our part
again, but instead we're modifying the size and the color to something different.
So real quick, let's just set the size equal to a new random size like one, one one.
And let's set the color equal to some kind of random color three.
So color three dot new.
Let's just do black right.
So we're playing this first tween.
And then five seconds later we're going to be playing this second tween.
And we're going to see a little bit of a conflict going on here.
And then finally actually let me adjust this tween info to be shorter.
So we're just going to do a tween info of just one second.
So we're going to have a timing conflict an issue here.
So if we play the game we're going to see the client perform the first tween which increases the size
and changes the color.
But after five seconds that tween is going to be overwritten.
There we go by our new tween.
So now this is the result of our object on all the clients in our game.
Oh, whoa, look at that.
You see the issue?
The server just set the property to that other tween that we were still waiting for.
Remember that one tween that had a time of 10s?
Well, that delay time finally went up and it set the properties on our instance to those old properties
when it should have gotten overwritten.
So a way we can fix this issue is we need to basically store the thread or the coroutine created by
the delay function, and we can store it in a table and use the instance as the key.
That way if this function gets called again and we're trying to tween the same instance while another
tween is active.
We're basically going to cancel that previous tween and instead do the new tween.
So this is very simple to do.
We can just create a table.
We'll call this active tweens.
And inside of the active tweens table we're going to use our instance as the key in this table.
And we're going to store the thread that gets returned by task dot delay.
So let me move this down here and we'll set that equal to this thread.
So now what we can do is we can check if there is an active thread on this particular instance.
So when we call the tween function what we're going to do is we're going to check if there is an active
tween or this instance.
If there is, we need to cancel it.
So let's go ahead and do task dot cancel.
And we need to pass the active thread.
And we should be good to go.
So let's play test the game again and see if that has resolved our timing issue.
So here are the first tween is playing and then the second tween plays.
And let's see if the server sets the property for this part to those old properties.
And we're waiting.
We're waiting.
Looks like we fixed it.
Let's go ahead and take a look at the server view.
And perfect.
The server has the exact same view as the client.
One more important thing we need to do is that after we are done delaying and applying the properties,
we need to go ahead and remove that tween out of the active tweens table to clean up memory so we can
do active tweens.
Instance is equal to nil just like that.
So now we basically have a working tween system on the server that we can use that will notify all the
clients in our game.
And once the tween is over, the server goes through and applies all of the correct properties.
So any new clients in the future that join will see the correct properties on a particular instance.
Now just to clean this up a little bit more, let's go ahead and move this function into its own function
outside of this scope, this scope of the tween function.
Let's call this function tween completed.
And we're going to need to be passed the instance and the goal.
And then we can just basically copy this code here, paste it inside of there, and instead we can delay
our tween completed function and the arguments we need to pass to.
It's going to be the instance and the goal.
So we can pass instance and we can pass the goal.
So these two arguments will automatically get passed to our tween completed function.
And it should do the exact same thing.
And now one more thing I promise we need to account for if the repeat count is negative one, which
is an issue because we can't really loop tweens on the server with this setup.
So as basically a band aid fix, what we can do is we can check if tween info dot repeat count is equal
to negative one.
If it is, then we can just basically give out a warning and we could say cannot repeat tweens with
better tween or something like that, because that's a little bit of a headache we don't want to deal
with and we'll just return.
Okay, I lied.
There's actually one more thing we need to do with our better twin module, and we need to account for
if this reverse is property is set to true.
And I'll show you why here in a second.
So let's go back to our script that handles resizing or tweening that part.
And I'm going to delete this.
And what we want to do is let's go to modify this tween info.
We'll just do an enum easing style of linear.
We'll do an enum easing direction of the regular in because we want to get to, uh, the reverses.
Let's just set the repeat count to one and then reverses.
We're going to set this to true.
Um, okay.
Yeah.
Good.
We'll set reverse is equal to true.
So what's going to happen is that this tween is going to play.
It's going to go to the goal.
And then it's going to reverse and go back to its default state.
That is what this part is going to do.
Let's decrease the time here.
And that looks good.
So let's go and play test the game.
And we're going to have this tween happen here.
And what the issue is going to be is I think the server is going to prematurely.
Yeah there's your issue.
There is your issue.
The tween ended prematurely and it also set it to the wrong property.
The tween should be oh it's still playing okay.
Let's just keep it playing and see what the end goal is.
We'll get to the end goal okay perfect.
This is what the tween should look like for all the clients in the game.
But if we look at the server, this is very wrong.
This is not what we want at all.
And that's because we did not account for this reverse property.
So basically what we need to do is we need to multiply the time by two.
If reverses is set to two.
Otherwise we can just multiply it by one and or just leave time the same.
So let's make a variable called time multiplier.
And what we need to do is we need to check if reverses is set to true.
So I'm going to do an if then else expression here real quick, which is basically an easier to read
version of using those expressions that we saw earlier like and and or so like I could do tween info
dot reverses and 2 or 1, but that's a little bit hard to read.
A little easier way to read this would be if tween info dot reverses, then the value we're going to
set in time multiplier is going to be two.
Otherwise it's going to be one.
This is an if then else expression.
It's not an if then else statement because there's no end keyword here.
We don't need that.
We are using this as a way to store a value in a variable based on a condition.
So now what we can do is we can multiply twin info dot time by this time multiplier.
And if we do reverse we basically just need to not apply any of the gold properties because it's going
to go back to its default state.
So the easiest way we could do that is we could pass our tween info to the tween completed function,
and then we could check in there if it reverses.
And if it does we don't do anything.
Or we could do some other way.
But let's just do that for now.
We can get the tween info and if this tween info reverses, then we basically do nothing.
But we still need to set this equal to nil.
So actually if the tween info does not reverse, we'll apply the properties and then we'll make sure
to set active tweens for this instance equal to nil.
Okay.
So now that issue we just saw should be resolved.
So let's go back and play test.
And let's wait for that tween to finish up.
Okay.
There is the final result for the tween.
Let's check the server.
And perfect.
The server didn't do anything.
And the part looks correct on both the client and the server.
Man I keep telling you we're done and I keep lying to you.
I'm so sorry, but one more thing I've added to the better tween tween function is I just return the
total amount of time.
So that way, anyone who's calling this function knows how long to wait for until the tween is finished.
That's the last thing I am doing.
All right.
Just to make sure you understand everything, we're just going to do a quick recap with our better tween
module and how it works.
So we have a function in our better tween module called tween.
And it's basically us just copying or replicating the create constructor function that is in the tween
service.
So we get passed the instance we want a tween, the tween info for the tween, and the goal table of
properties that we want a tween to.
And since this system tells all of the clients to play the tween, it's kind of difficult for us to
be able to track, for example, an infinite tween.
So what we just do in the meantime is we just spit out a warning saying, hey, we can't play any tweens
on the server side using this module when the repeat count is set to negative one, which means this
tween goes on forever and ever.
And that's kind of an issue.
So we just say, hey, we can't do that.
Otherwise.
What we need to do is we need to check if this instance already has a tween active in our active tweens
table, and we use the instance as the key in the table.
And if there is a current thread in here, maybe it's suspended or whatever.
We use the task dot cancel function to cancel that thread and make way for the new thread we're about
to create.
So then we take our tween info, we unpack all of its data and place it into a tween data table.
That way we can actually pass it through our remote event, because for some reason we aren't able to
send tween infos through remote events.
So we need to do it this way.
And then the next thing we need to do is calculate the total time for the tween.
Now if this tween reverses, we need to multiply our time by basically two to account for if the tween
reverses.
So we check.
If the tween reverses then we're going to set time multiplier to two.
Otherwise we just set it to one.
And then we calculate the total time, which is going to be the duration of the tween multiplied by
that time multiplier.
And then we need to add if there is going to be a delay time.
And then once we get this value, we need to multiply it by how many times this tween repeats.
By default this is set to zero, which is why we're adding one here.
Because if we multiply this number by zero, we're just going to get a total time of zero, which isn't
what we want.
And then once we're done calculating the total time, we're going to delay a new coroutine.
So we're going to pass the total time, however long that is.
And after that time is up, we're going to execute our tween completed function.
And then these values that we're passing to the task dot delay function after this one are going to
be all of the arguments we're passing to the tween completed function.
Once this total time is up, it'll go in here and execute this function.
But before we do that, we're going to set in our active tweens table.
Set it equal to this instance.
And we're going to store the new thread or the coroutine.
And then we fire to all the clients.
Hey play this tween and we return the total amount of time that this tween plays for.
And then inside of our local script that's listening to that event, we get passed the instance that
table containing all of the data for the tween as well as the goal table.
If we do not have access to this instance on the client side, it could be maybe this instance hasn't
been replicated yet or something like that.
Then we're just going to return because we can't do anything otherwise.
We take our tween data table and we unpack all of the values in there and give it to our tween info
dot new function.
So that way we actually have a tween info data type on the client side.
And then we can pass that information to the tween service create function.
So we give it the instance, we give it the tween info, we give it the goal and we simply play the
tween.
Now when the tween is over, let's say this total time duration is up.
It's going to execute this function, which just basically checks to see if the tween info does not
reverse, and if it does not reverse, it's going to go through every single property and value inside
of the goal table and apply it on the instance on the server side.
That way, any future clients that join our game are going to have the same properties applied on the
instance.
So that way none of the clients in the game are out of sync based on whatever property we're Tweening
if the tween does reverse, then there's no point for us to apply any of the goal properties because
it'll go and tween to the goal properties, and then it reverses and just goes back to its regular state.
So there's no point applying any of the properties.
And then once that's done, we need to make sure we clear this instance and the key and the value out
of our active tweens table.
So we just set it equal to nil.
And that's how our better tween system works.
Alrighty.
So this was a butt ton of information I just threw at your face.
I'm sorry, but I'm also not sorry.
After this lecture, you're going to attempt a quiz, and then we're going to practice using our better
tween module in another lecture for creating this sliding door that opens and then we're able to close
it.
So thank you for watching and I will see you there.